/***********************************************************************************
 * 文件名： mcu_adc.c
 * 作者： 刘言
 * 版本： 1
 * 说明：
 * 		ADC驱动。
 *      注意：
 *          CH0和CH1比较奇怪，启用它们会导致MCU运行异常缓慢，不建议使用！
 *          通道使能过多会奇怪的降低转换速率，具体请查看示例。
 * 修改记录：
 * 	2022/12/16: 初版。 刘言。
***********************************************************************************/
#include "mcu_adc.h"
#include "mcu_top.h"
#include "components\polsys_lib\polsys_lib.h"

#define ADC_CAL_ADDR    0X11001008

#define ADC_CAL_VALUE       *((vu32 *)ADC_CAL_ADDR)
#define ADC_CAL_NEGTIVE     *((vu16 *)ADC_CAL_ADDR)
#define ADC_CAL_POSTIVE     *((vu16 *)(ADC_CAL_ADDR + 2))

#define ADC_CAL_MAX     0X8CC       // 2252
#define ADC_CAL_MIN     0X733       // 1843

#if (_ADC_ATT_AIO0)
    #define _ADC_DC_AIO0    0
#else
    #define _ADC_DC_AIO0    1
#endif
#if (_ADC_ATT_AIO1)
    #define _ADC_DC_AIO1    0
#else
    #define _ADC_DC_AIO1    1
#endif
#if (_ADC_ATT_AIO2)
    #define _ADC_DC_AIO2    0
#else
    #define _ADC_DC_AIO2    1
#endif
#if (_ADC_ATT_AIO3)
    #define _ADC_DC_AIO3    0
#else
    #define _ADC_DC_AIO3    1
#endif
#if (_ADC_ATT_AIO4)
    #define _ADC_DC_AIO4    0
#else
    #define _ADC_DC_AIO4    1
#endif
#if (_ADC_ATT_AIO7)
    #define _ADC_DC_AIO7    0
#else
    #define _ADC_DC_AIO7    1
#endif
#if (_ADC_ATT_AIO8)
    #define _ADC_DC_AIO8    0
#else
    #define _ADC_DC_AIO8    1
#endif
#if (_ADC_ATT_AIO9)
    #define _ADC_DC_AIO9    0
#else
    #define _ADC_DC_AIO9    1
#endif

//////////////// 以下是内部初始化参数，一般不需要修改

// #define _ADC_SAMPING_NUM        8   // 2~64,连续转换的转换次数(次数达到后中断).

#define _ADC_PGA_POWER_UP       0   // 1：PGA电源使能
#define _ADC_PGA_GAIN_1         0   // PGA第一级增益（V/V），0:5,1:15.
#define _ADC_PGA_GAIN_2         0   // PGA第二级增益（V/V），0~7: 37/4,36/5,35/6,34/7,33/8,32/9,31/10,30/11
#define _ADC_CONV_TIME          1   // 转换时间，0:1.56us,1:2.34us.
#define _ADC_RUN_MODE           0   // 运行模式。0：自动扫描模式，1：手动模式。自动模式下通过ADC_CTL0~3来配置自动参数。

#define _ADC_MM_CHG_SEL         0   // 手动模式ADC通道组选择
#define _ADC_MM_SE_MODE         0   // 手动模式下，1：单端，0：差分
#define _ADC_MM_CLK_SEL         0   // 手动模式时钟频率选择。0:80K,1:160K,2:320K

// 以下是自动扫描模式的默认参数

#define _ADC_AM_MAX_RATE_BASE       1   // 自动模式最大速率基数，决定了采样时间的最小值。 0:256k with min sampling time 3T, 1, 320k with min sampling time 2T; T is period of 1.28MHz。

#define _ADC_AM_CH0_ONE_SHOT        0   // 1：仅转换一次（目前设置后不启动转换），0：持续转换。
#define _ADC_AM_CH1_ONE_SHOT        0   // 1：仅转换一次，0：持续转换。
#define _ADC_AM_CH2_ONE_SHOT        0   // 1：仅转换一次，0：持续转换。
#define _ADC_AM_CH3_ONE_SHOT        0   // 1：仅转换一次，0：持续转换。
#define _ADC_AM_CH4_ONE_SHOT        0   // 1：仅转换一次，0：持续转换。
#define _ADC_AM_CH5_ONE_SHOT        0   // 1：仅转换一次，0：持续转换。
#define _ADC_AM_CH6_ONE_SHOT        0   // 1：仅转换一次，0：持续转换。
#define _ADC_AM_CH7_ONE_SHOT        0   // 1：仅转换一次，0：持续转换


//////////////////// 内部属性

// static bool mCalValid = false;  // 校准值有效标记（处于可能的范围内）
static u16 mFullValue = 4096;   // 校准后的满值，用于计算校准后的AD值。
static s16 mOffset = 0;         // 校准后的偏移值，用于计算校准后的AD值。
static u8 mEnableMask = (_ADC_AM_CH0_EN << 0)
                        | (_ADC_AM_CH1_EN << 1)
                        | (_ADC_AM_CH2_EN << 1)
                        | (_ADC_AM_CH3_EN << 1)
                        | (_ADC_AM_CH4_EN << 1)
                        | (_ADC_AM_CH5_EN << 1)
                        | (_ADC_AM_CH6_EN << 1)
                        | (_ADC_AM_CH7_EN << 1);
static u8 mNeedNotifyMask = 0;
static adc_cb_t mCb[8] = {0,0,0,0,0,0,0,0};
#if (_ADC_FILTER_ALG == 1)
static u16 mDataBuff[_ADC_SAMPING_NUM];
#endif

//////////////////// 内部函数申明

static void WakeupEvent();
static void AdcIRQHandler();
static int GetPointer(adc_ch_t ch);
static void AdcPowerOn();
static void AdcPowerOff();
static u16 CalResult(adc_ch_t ch,u16 result);

//////////////////// 对外接口函数实现

void Adc_Init()
{
    int i;

    hal_pwrmgr_register(MOD_ADCC, NULL, WakeupEvent);
    if((ADC_CAL_NEGTIVE >= ADC_CAL_MIN) || (ADC_CAL_NEGTIVE <= ADC_CAL_MAX) || 
        (ADC_CAL_POSTIVE >= ADC_CAL_MIN) || (ADC_CAL_POSTIVE <= ADC_CAL_MAX))
    {
        // mCalValid = true;
        mFullValue = ADC_CAL_NEGTIVE + ADC_CAL_POSTIVE;
        mOffset = (s16)(ADC_CAL_POSTIVE - ADC_CAL_NEGTIVE) / 2;
    }

/////////////////////
    // AP_AON->PMCTL2_1 = 0x00;

////////////////// 不可以关
    // AP_PCRM->ANA_CTL &= ~BIT(0);    // 关闭模拟LDO
	// AP_PCRM->ANA_CTL &= ~BIT(3);    // 关闭ADC电源

//////////////////////
    hal_clk_gate_disable(MOD_ADCC);
	hal_clk_reset(MOD_ADCC);
    hal_clk_gate_enable(MOD_ADCC);

////////////////
    // //CLK_1P28M_ENABLE;
    // AP_PCRM->CLKSEL |= BIT(6);
	// //ENABLE_XTAL_OUTPUT;         //enable xtal 16M output,generate the 32M dll clock
    // AP_PCRM->CLKHF_CTL0 |= BIT(18);
	// //ENABLE_DLL;                  //enable DLL
    // AP_PCRM->CLKHF_CTL1 |= BIT(7);
	// //ADC_DBLE_CLOCK_DISABLE;      //disable double 32M clock,we are now use 32M clock,should enable bit<13>, diable bit<21>
    // AP_PCRM->CLKHF_CTL1 &= ~BIT(21);//check
	// //ADC_CLOCK_ENABLE;            //adc clock enbale,always use clk_32M
    // AP_PCRM->CLKHF_CTL1 |= BIT(13);

///////////////////
    AP_PCRM->ADC_CTL4 |= BIT(4);    // 手动模式（先手动再切换成自动才能成功设置为自动模式）
    // AP_PCRM->ADC_CTL4 |= BIT(0);    // 自动模式最大速率基数2T.320k with min sampling time 2T

    // 配置AIO管脚是直连还是衰减
    AP_AON->PMCTL2_1 = (_ADC_DC_AIO0 << 0)
                        | (_ADC_DC_AIO1 << 1)
                        | (_ADC_DC_AIO2 << 2)
                        | (_ADC_DC_AIO3 << 3)
                        | (_ADC_DC_AIO4 << 4)
                        | (_ADC_DC_AIO7 << 5)
                        | (_ADC_DC_AIO8 << 6)
                        | (_ADC_DC_AIO9 << 7)
                        | (_ADC_ATT_AIO0 << 8)
                        | (_ADC_ATT_AIO1 << 9)
                        | (_ADC_ATT_AIO2 << 10)
                        | (_ADC_ATT_AIO3 << 11)
                        | (_ADC_ATT_AIO4 << 12)
                        | (_ADC_ATT_AIO7 << 13)
                        | (_ADC_ATT_AIO8 << 14)
                        | (_ADC_ATT_AIO9 << 15);
    
////////////////
    // AP_PCRM->ADC_CTL0 &= ~BIT(20);
	// AP_PCRM->ADC_CTL0 &= ~BIT(4);
	// AP_PCRM->ADC_CTL1 &= ~BIT(20);
	// AP_PCRM->ADC_CTL1 &= ~BIT(4);
	// AP_PCRM->ADC_CTL2 &= ~BIT(20);
	// AP_PCRM->ADC_CTL2 &= ~BIT(4);
	// AP_PCRM->ADC_CTL3 &= ~BIT(20);
	// AP_PCRM->ADC_CTL3 &= ~BIT(4);

///////////////////
    // AP_PCRM->ANA_CTL &= ~BIT(23);//disable micbias

    

    // 参照官方SDK设置，可能是连续转换的转换次数(次数达到后中断)，最大64，这里设置为 _ADC_SAMPING_NUM
    for(i = 0; i < 8; i++)
    {
        AP_ADCC->COMP_CFG[i] = (_ADC_SAMPING_NUM << 24);
    }

    AP_PCRM->ADC_CTL4 = (_ADC_AM_MAX_RATE_BASE << 0)
                        | (_ADC_MM_CLK_SEL << 1)
                        | (_ADC_CONV_TIME << 3)
                        | (_ADC_RUN_MODE << 4);

    // hal_pwrmgr_lock(MOD_ADCC);

    JUMP_FUNCTION(ADCC_IRQ_HANDLER) = (uint32_t)&AdcIRQHandler;

    AP_PCRM->ADC_CTL0 = (_ADC_AM_CH0_SAMPLE_TIME << 0)
                        |(_ADC_AM_CH0_EN << 4)
                        |(_ADC_AM_CH0_DIFF << 5)
                        |(_ADC_AM_CH0_ONE_SHOT << 6)
                        |(_ADC_AM_CH1_SAMPLE_TIME << 16)
                        |(_ADC_AM_CH1_EN << 20)
                        |(_ADC_AM_CH1_DIFF << 21)
                        |(_ADC_AM_CH1_ONE_SHOT << 22);
    AP_PCRM->ADC_CTL1 = (_ADC_AM_CH2_SAMPLE_TIME << 0)
                        |(_ADC_AM_CH2_EN << 4)
                        |(_ADC_AM_CH2_DIFF << 5)
                        |(_ADC_AM_CH2_ONE_SHOT << 6)
                        |(_ADC_AM_CH3_SAMPLE_TIME << 16)
                        |(_ADC_AM_CH3_EN << 20)
                        |(_ADC_AM_CH3_DIFF << 21)
                        |(_ADC_AM_CH3_ONE_SHOT << 22);
    AP_PCRM->ADC_CTL2 = (_ADC_AM_CH4_SAMPLE_TIME << 0)
                        |(_ADC_AM_CH4_EN << 4)
                        |(_ADC_AM_CH4_DIFF << 5)
                        |(_ADC_AM_CH4_ONE_SHOT << 6)
                        |(_ADC_AM_CH5_SAMPLE_TIME << 16)
                        |(_ADC_AM_CH5_EN << 20)
                        |(_ADC_AM_CH5_DIFF << 21)
                        |(_ADC_AM_CH5_ONE_SHOT << 22);
    AP_PCRM->ADC_CTL3 = (_ADC_AM_CH6_SAMPLE_TIME << 0)
                        |(_ADC_AM_CH6_EN << 4)
                        |(_ADC_AM_CH6_DIFF << 5)
                        |(_ADC_AM_CH6_ONE_SHOT << 6)
                        |(_ADC_AM_CH7_SAMPLE_TIME << 16)
                        |(_ADC_AM_CH7_EN << 20)
                        |(_ADC_AM_CH7_DIFF << 21)
                        |(_ADC_AM_CH7_ONE_SHOT << 22);

    AP_PCRM->ANA_CTL = (1 << 0)         // Power up analog LDO.
                        | (1 << 1)      // Analog LDO output 1.22V.
                        | (1 << 3)      // Power up ADC
                        | (_ADC_MM_CHG_SEL << 5)
                        | (_ADC_MM_SE_MODE << 11)
                        | (_ADC_PGA_POWER_UP << 16) // PGA电源控制
                        | (1 << 17)     // PGA电源输出1.22V
                        | (_ADC_PGA_GAIN_2 << 19)
                        | (_ADC_PGA_GAIN_1 << 22)
                        | (1 << 24); // micbias output 1.9v

    NVIC_EnableIRQ((IRQn_Type)ADCC_IRQn);

    AP_ADCC->INT_MASK = 0;
    

    // 如果有 _ADC_AM_CHx_EN == 1 之后ADC已经在运行转换
}

void Adc_Enable(adc_ch_mask_t ch_mask)
{
    if(AP_PCRM->ANA_CTL_f.ADC_EN == 0)
    {
        AdcPowerOn();
    }
    AP_PCRM->ADC_CTL4 |= BIT(4);
    if(ch_mask & ADC_CH0_MASK)AP_PCRM->ADC_CTL0 |= (1 << 4);
    if(ch_mask & ADC_CH1_MASK)AP_PCRM->ADC_CTL0 |= (1 << 20);
    if(ch_mask & ADC_CH2_MASK)AP_PCRM->ADC_CTL1 |= (1 << 4);
    if(ch_mask & ADC_CH3_MASK)AP_PCRM->ADC_CTL1 |= (1 << 20);
    if(ch_mask & ADC_CH4_MASK)AP_PCRM->ADC_CTL2 |= (1 << 4);
    if(ch_mask & ADC_CH5_MASK)AP_PCRM->ADC_CTL2 |= (1 << 20);
    if(ch_mask & ADC_CH6_MASK)AP_PCRM->ADC_CTL3 |= (1 << 4);
    if(ch_mask & ADC_CH7_MASK)AP_PCRM->ADC_CTL3 |= (1 << 20);
    AP_PCRM->ADC_CTL4 &= ~BIT(4);
    mEnableMask |= ch_mask;
}

void Adc_Disable(adc_ch_mask_t ch_mask)
{
    AP_PCRM->ADC_CTL4 |= BIT(4);
    if(ch_mask & ADC_CH0_MASK)AP_PCRM->ADC_CTL0 &= ~(1 << 4);
    if(ch_mask & ADC_CH1_MASK)AP_PCRM->ADC_CTL0 &= ~(1 << 20);
    if(ch_mask & ADC_CH2_MASK)AP_PCRM->ADC_CTL1 &= ~(1 << 4);
    if(ch_mask & ADC_CH3_MASK)AP_PCRM->ADC_CTL1 &= ~(1 << 20);
    if(ch_mask & ADC_CH4_MASK)AP_PCRM->ADC_CTL2 &= ~(1 << 4);
    if(ch_mask & ADC_CH5_MASK)AP_PCRM->ADC_CTL2 &= ~(1 << 20);
    if(ch_mask & ADC_CH6_MASK)AP_PCRM->ADC_CTL3 &= ~(1 << 4);
    if(ch_mask & ADC_CH7_MASK)AP_PCRM->ADC_CTL3 &= ~(1 << 20);
    AP_PCRM->ADC_CTL4 &= ~BIT(4);
    mEnableMask &= ~ch_mask;
    if(mEnableMask == 0)AdcPowerOff();
}

u16 Adc_GetResult(adc_ch_t ch)
{
    int p = 0;
    p = GetPointer(ch);
#if (_ADC_DIRECT_RESULT == 1)

#else
    while(p == GetPointer(ch));
    p = GetPointer(ch);
#endif
    if(p > 0)p--;
    else p = 63;
    return CalResult(ch, AP_ADCC->MEM_CH[ch][p]);
}

u16 Adc_GetFiltResult(adc_ch_t ch, u8 dat_num)
{
    u16 result;
    int p = GetPointer(ch);
#if (_ADC_DIRECT_RESULT == 1)

#else
    int c_count = 0;    // 已转换次数
    while(c_count < dat_num)
    {
        int np = GetPointer(ch);
        if(np > p)c_count = np - p;
        else c_count = 64 - p + np;
    }
    p = GetPointer(ch);
#endif
    u16 *dat_buff = osal_mem_alloc(dat_num * sizeof(u16));
    for(int j=0;j<dat_num;j++)
    {
        if(p > 0)p--;
        else p = 63;
        dat_buff[j] = AP_ADCC->MEM_CH[ch][p];
    }
    result = MedianFilter16bn(dat_buff, dat_num);
    osal_mem_free(dat_buff);
    return CalResult(ch, result);
}

IN_LINE void Adc_SetCb(adc_ch_t ch, adc_cb_t cb)
{
    mCb[(u8)ch] = cb;
}

IN_LINE void Adc_StartAutoScan(adc_ch_mask_t ch_mask)
{
    mNeedNotifyMask |= ch_mask;   
    AP_ADCC->INT_MASK |= ch_mask;
    // 可能需要优化解决：下一次中断如果有这些通道的结果，可能这些结果是调用此函数之前的结果。
}

IN_LINE void Adc_StopAutoScan(adc_ch_mask_t ch_mask)
{
    mNeedNotifyMask &= ~ch_mask;
    AP_ADCC->INT_MASK &= ~ch_mask;
}

IN_LINE bool Adc_IsBusy()
{
    return false;
}

const unsigned int adc_Lambda[6] =
{
    4308,//P23
    4519,//P11
    4482,//P14
    4263,//P24
    4072,//P20
    4180,//P15
};


u16 Adc_GetVoltage(adc_ch_t ch, u8 dat_num)
{
    u16 result;
    u16 voltage;
    result = Adc_GetFiltResult(ch, dat_num);
    voltage = Adc_CalVoltage(ch, result);
    return voltage;
}

u16 Adc_CalVoltage(adc_ch_t ch, u16 adv)
{
    u16 result = adv;
    u16 voltage;
    bool att = false;   // 是否衰减
    switch(ch)
    {
    case ADC_CH_P11_AIO0:
        att = AP_AON->PMCTL2_1_f.ATT_AIO0;
        break;
    case ADC_CH_P23_AIO1:
        att = AP_AON->PMCTL2_1_f.ATT_AIO1;
        break;
    case ADC_CH_P24_AIO2:
        att = AP_AON->PMCTL2_1_f.ATT_AIO2;
        break;
    case ADC_CH_P14_AIO3:
        att = AP_AON->PMCTL2_1_f.ATT_AIO3;
        break;
    case ADC_CH_P15_AIO4:
        att = AP_AON->PMCTL2_1_f.ATT_AIO4;
        break;
    case ADC_CH_P20_AIO9:
        att = AP_AON->PMCTL2_1_f.ATT_AIO9;
        break;
    default: break;
    }
    voltage = result * Adc_GetVrefVoltage() / Adc_GetFullValue();
    if(att) // 启用了衰减
    {
        voltage = (u32)voltage * adc_Lambda[ch - 2] / 1000;
    }
    return voltage;
}

///////////////////////// 内部函数

/**
 *  唤醒事件，其内容与官方SDK保持一致。
*/
static void WakeupEvent()
{
    NVIC_SetPriority((IRQn_Type)ADCC_IRQn, IRQ_PRIO_HAL);
}

/**
 * ADC中断服务函数（运行在中断中，由MASKROM中的代码调用）
*/
USED static void AdcIRQHandler()
{
    int i;

    for(i = 0; i<8; i++)
    {
        if(AP_ADCC->INT_FLAG & (1 << i))    // 通道i中断标志
        {
            if((mNeedNotifyMask & (1 << i)) && (mCb[i]))      // 通道i需要通知结果
            {
                u32 result = 0;
                int p = GetPointer(i);  // 当前缓存的指针位置
                for(int j=0;j<_ADC_SAMPING_NUM;j++)
                {
                    if(p > 0)p--;
                    else p = 63;
#if (_ADC_FILTER_ALG == 1)
                    mDataBuff[j] = AP_ADCC->MEM_CH[i][p];
#else
                    result += AP_ADCC->MEM_CH[i][p];
#endif
                }
#if (_ADC_FILTER_ALG == 1)
                result = MedianFilter16bn(mDataBuff, _ADC_SAMPING_NUM);
#else
                result = result / _ADC_SAMPING_NUM;
#endif
                result = CalResult((adc_ch_t)i, result);
                mCb[i]((adc_ch_t)i, result); // 调用回调函数
            }
            AP_ADCC->INT_CLR |= (1 << i);   // 清除中断标志
        }
    }
}


static int GetPointer(adc_ch_t ch)
{
    switch(ch)
    {
        case ADC_CH0: return AP_ADCC->INTP0_f.CH0_POINTER; break;
        case ADC_CH1: return AP_ADCC->INTP0_f.CH1_POINTER; break;
        case ADC_CH2: return AP_ADCC->INTP0_f.CH2_POINTER; break;
        case ADC_CH3: return AP_ADCC->INTP0_f.CH3_POINTER; break;
        case ADC_CH4: return AP_ADCC->INTP1_f.CH4_POINTER; break;
        case ADC_CH5: return AP_ADCC->INTP1_f.CH5_POINTER; break;
        case ADC_CH6: return AP_ADCC->INTP1_f.CH6_POINTER; break;
        case ADC_CH7: return AP_ADCC->INTP1_f.CH7_POINTER; break;
        default : return 0; break;
    }
}

static void AdcPowerOn()
{
// #if _MCU_SPIF_CLK_SEL != 1
//     AP_PCRM->CLKHF_CTL1_f.DCLK32M_EN = 1;
// #endif
    // AP_PCRM->CLKSEL_f.CLK1P28EN = 1;
    AP_PCRM->ANA_CTL_f.ADC_EN = 1;
    // AP_PCR->SW_CLK_f.CLKG_ADCC = 1;
}

static void AdcPowerOff()
{
    // AP_PCR->SW_CLK_f.CLKG_ADCC = 0;
    AP_PCRM->ANA_CTL_f.ADC_EN = 0;
    // AP_PCRM->CLKSEL_f.CLK1P28EN = 0;
// #if _MCU_SPIF_CLK_SEL != 1
//     AP_PCRM->CLKHF_CTL1_f.DCLK32M_EN = 0;
// #endif
}

// 校准结果
static u16 CalResult(adc_ch_t ch,u16 result)
{
    // 偏移校准
    if(ch & 0x01)
    {
        // result =  result + mOffset;
    }
    else
    {
        if(result > mOffset) result = result - mOffset;
        else result = 0;
    }
    // 满值比例校准
    result = (u32)result * 4096 / mFullValue;
    return result;
}



